home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / tiff / tiffswap.c < prev    next >
Text File  |  1988-10-26  |  17KB  |  738 lines

  1. /* TiffSwap.c - convert a Motorola-style (MM) TIFF file to an Intel-style (II) TIFF file,
  2.  *              in place.
  3.  *
  4.  * If the TIFF file is already of type "II", it is converted to type "MM."
  5.  *
  6.  * Assumes that the image data itself does not need to be byte-swapped.  This is true
  7.  * with all currently defined compression schemes (as of TIFF 5.0), and with
  8.  * uncompressed data where BitsPerSample is less than or equal to 8.
  9.  *
  10.  * That is, if BitsPerSample is greater than 8, and the data is uncompressed, this
  11.  * program will not do its job properly.  The resulting file will appear to work, since
  12.  * the "header" information will be correct, but the image will display and print incorrectly.
  13.  * 
  14.  * If any field in the file is more than 64k bytes, it will not be byte swapped properly 
  15.  * on the PC.  
  16.  */
  17. #define     WINDOWS        1        /* define MACINTOSH if on MAC, WINDOWS if on PC AT */
  18. #include "stdio.h"
  19.  
  20. /* prototypes:
  21.  */
  22. #ifdef MACINTOSH
  23. int printf (char *, ...);
  24. FILE * fopen (char *, char *);
  25. int fseek (FILE *, long, int);
  26. int fread (char *, int, int, FILE *);
  27. int fwrite (char *, int, int, FILE *);
  28. int fclose (FILE *);
  29. char *mlalloc (unsigned long);
  30. int free (char *);
  31. #endif
  32.  
  33. #ifdef WINDOWS
  34. char * malloc(unsigned);
  35. #endif 
  36. /* basic data types -- may be different per machine/compiler
  37.  */
  38. typedef unsigned short        WORD;        /* 16-bit */
  39. typedef unsigned long        DWORD;        /* 32-bit */
  40. typedef int                    RC;            /* return code */
  41. typedef char                *LPSTR;
  42.  
  43.  
  44. #ifndef NULL
  45. #define        NULL            0L
  46. #endif
  47. #define        FAR
  48. #define        SUCCESS            0
  49. #define        LOCAL            static
  50. #define        INTELTIFF        (0x4949)
  51. #define        MOTOROLATIFF    (0x4D4D)
  52. #define        MAXSHORT        (0x7FFF)        /* maximum 16-bit signed int */
  53.  
  54. /* TIFF data types
  55.  */
  56. #define TIFFBYTE        1
  57. #define TIFFASCII        2
  58. #define TIFFSHORT        3
  59. #define TIFFLONG        4
  60. #define TIFFRATIONAL    5
  61.  
  62.  
  63. /* TIFF "header" (8 bytes)
  64.  * note: GtTiffHdr plays a little loose with this structure.
  65.  */
  66. typedef struct {
  67.         WORD    thByteOrder;
  68.         WORD    thVersion;
  69.         DWORD    thIfdOffset;
  70. } TIFFHDR;
  71.  
  72. /* IFD entry
  73.  * note: GtTiffEntry plays a little loose with this structure.
  74.  */
  75. typedef struct {
  76.         WORD  deTag;
  77.         WORD  deType;
  78.         DWORD deLength;
  79.         DWORD deVal;
  80. } DIRENTRY;
  81.  
  82. /* image data location
  83.  */
  84. typedef struct {
  85.     WORD        dlWhere;
  86. #define                INFILE    1
  87. #define                INTABLE    2
  88.     FILE        *dlFp;
  89.     LPSTR        dlTable;    /* address of locked-down table bytes */
  90.     WORD        dlOrder;    /* INTELTIFF or MOTOROLATIFF.  
  91.                              * relevant only when reading data.
  92.                              */
  93. } DLOC;
  94.  
  95.  
  96. /* a particularly greasy static:
  97.  */
  98. DWORD TiffStart = 0L;
  99.  
  100. /***************************** subroutines ***************************/
  101.  
  102. /* swap bytes -- overlapping arrays are handled properly
  103.  */
  104. void swab (LPSTR,LPSTR,WORD);
  105. static void swab (lpSrc, lpDst, nbytes)
  106. register LPSTR    lpSrc, lpDst;    /* assumed to be word-aligned */
  107. WORD              nbytes;            /* assumed to be even */
  108. {
  109.         register WORD words;
  110.         union {
  111.             char c[2];
  112.             WORD w;
  113.         } wrd;
  114.  
  115.         words = nbytes/2;
  116.  
  117.         if (lpDst <= lpSrc || lpDst >= lpSrc + nbytes) {
  118.             for (; words--; lpSrc += 2) {
  119.                 wrd.w = *(WORD FAR *)lpSrc;
  120.                 *lpDst++ = *(LPSTR)(wrd.c + 1);    /* W2 doesn't like wrd.c[1] */
  121.                 *lpDst++ = *(LPSTR)(wrd.c);
  122.             }
  123.         }
  124.         else {        /* we'll have to go backward */
  125.             lpSrc += nbytes - sizeof(WORD);
  126.             lpDst += nbytes - 1;
  127.             for (; words--; lpSrc -= 2) {
  128.                 wrd.w = *(WORD FAR *)lpSrc;
  129.                 *lpDst-- = *(LPSTR)(wrd.c);
  130.                 *lpDst-- = *(LPSTR)(wrd.c + 1);
  131.             }
  132.         }
  133. }
  134.  
  135. /* swap words -- overlapping ranges are handled properly
  136.  *
  137.  * actually, does a 4-byte reversal, not a swap of words within double words
  138.  */
  139. void swaw (LPSTR,LPSTR,WORD);
  140. LOCAL void swaw (lpSrc, lpDst, nbytes)
  141. register LPSTR    lpSrc, lpDst;    /* assumed to be word-aligned */
  142. WORD              nbytes;            /* assumed to be multiple of 4 */
  143. {
  144.         register WORD dwords;
  145.         union {
  146.             char c[4];
  147.             DWORD dw;
  148.         } dwrd;
  149.  
  150.         dwords = nbytes/4;
  151.  
  152.         if (lpDst <= lpSrc || lpDst >= lpSrc + nbytes) {
  153.             for (; dwords--; lpSrc += 4) {
  154.                 dwrd.dw = *(DWORD FAR *)lpSrc;
  155.                 *lpDst++ = *(LPSTR)(dwrd.c + 3);
  156.                 *lpDst++ = *(LPSTR)(dwrd.c + 2);
  157.                 *lpDst++ = *(LPSTR)(dwrd.c + 1);
  158.                 *lpDst++ = *(LPSTR)(dwrd.c);
  159.             }
  160.         }
  161.         else {        /* we'll have to go backward */
  162.             lpSrc += nbytes - sizeof(DWORD);
  163.             lpDst += nbytes - 1;
  164.             for (; dwords--; lpSrc -= 4) {
  165.                 dwrd.dw = *(DWORD FAR *)lpSrc;
  166.                 *lpDst-- = *(LPSTR)(dwrd.c);
  167.                 *lpDst-- = *(LPSTR)(dwrd.c + 1);
  168.                 *lpDst-- = *(LPSTR)(dwrd.c + 2);
  169.                 *lpDst-- = *(LPSTR)(dwrd.c + 3);
  170.             }
  171.         }
  172. }
  173.  
  174. RC GtTiffSizeof (WORD, WORD *);
  175. RC GtTiffSizeof (n, p)
  176. WORD n;        /* TIFFBYTE or ... */
  177. WORD *p;    /* output */
  178. {
  179.     RC err = SUCCESS;
  180.  
  181.     switch (n) {
  182.     case TIFFBYTE:
  183.     case TIFFASCII:
  184.         *p = 1;
  185.         break;
  186.     case TIFFSHORT:
  187.         *p = 2;
  188.         break;
  189.     case TIFFLONG:
  190.         *p = 4;
  191.         break;
  192.     case TIFFRATIONAL:
  193.         *p = 8;
  194.         break;
  195.     default:
  196.         *p = 1;
  197.         err = -1;
  198.         break;
  199.     }
  200.     return err;
  201. }
  202.  
  203. /* get data -- handles file/table and byte-order problems
  204.  * 64K max
  205.  */
  206. RC GtData (DLOC *, DWORD, WORD, WORD, LPSTR);
  207. LOCAL RC GtData (pDloc, pos, n, dtype, lpData)
  208. DLOC    *pDloc;        /* data location - open file or locked-down table */
  209. DWORD    pos;        /* file/table position, with respect to its beginning */
  210. WORD    n;            /* number of data elements to read */
  211. WORD    dtype;        /* data type: TIFFSHORT, etc */
  212. LPSTR    lpData;        /* where to put the data */
  213. {
  214.         RC        err;
  215.         WORD    tsize;
  216.         WORD    BytesToRead;
  217.         int        red;        /* # of bytes read */
  218.         int        ii;
  219.  
  220.         if (n == 0)
  221.             goto done;
  222.             
  223.         /* read the data
  224.          */
  225.         if (err = GtTiffSizeof (dtype, &tsize)) {
  226.             printf ( "GtData: bad dtype\n");
  227.             return err;
  228.         }
  229.         BytesToRead = tsize * n;
  230.         if (pDloc->dlWhere == INFILE) {
  231.             if (err = fseek (pDloc->dlFp, (long) (pos+TiffStart), 0)) {
  232.                 printf ( "GtData: fseek error\n");
  233.                 return err;
  234.             }
  235.             if ((red = fread (lpData, 1, BytesToRead, pDloc->dlFp)) == 0) {
  236.                 printf ( "GtData: fread error\n");
  237.                 return -1;
  238.             }
  239.         }
  240.         else if (pDloc->dlWhere == INTABLE) {
  241.             printf ( "GtData: INTABLE not implemented here.\n");
  242.             return -1;
  243.         }
  244.         else {
  245.             printf ( "GtData: bad dlWhere\n");
  246.             return -1;
  247.         }
  248.  
  249.         /* change the byte order, if necessary
  250.          */
  251. #ifdef WINDOWS
  252.         if (pDloc->dlOrder == MOTOROLATIFF) {
  253. #endif
  254. #ifdef MACINTOSH
  255.         if (pDloc->dlOrder == INTELTIFF) {
  256. #endif
  257.             if (dtype == TIFFSHORT)
  258.                 swab (lpData, lpData, BytesToRead);
  259.             else if (dtype == TIFFLONG)
  260.                 swaw (lpData, lpData, BytesToRead);
  261.             else if (dtype == TIFFRATIONAL)
  262.                 swaw (lpData, lpData, BytesToRead);
  263.         }
  264.  
  265.         /* return
  266.          */
  267. done:    return SUCCESS;
  268. }
  269.  
  270. /* get TIFF 8-byte header
  271.  * currently only probably portable.  depends somewhat on compiler's 
  272.  * structure organization.
  273.  */
  274. RC GtTiffHdr (DLOC *, TIFFHDR *);
  275. LOCAL RC GtTiffHdr (pDloc, pHdr)
  276. DLOC *pDloc;
  277. TIFFHDR *pHdr;
  278. {
  279.         RC err;
  280.  
  281.         /* get the first 2 words
  282.          */
  283.         if (err = GtData (pDloc, (DWORD) 0, 2, TIFFSHORT, 
  284.          (LPSTR)&pHdr->thByteOrder)) {
  285.             return err;
  286.         }
  287.  
  288.         /* get the double word (IFD offset)
  289.          */
  290.         if (err = GtData (pDloc, (DWORD)4, 1, TIFFLONG, 
  291.          (LPSTR)&pHdr->thIfdOffset)) {
  292.             return err;
  293.         }
  294.  
  295.         /* return
  296.          */
  297.         return SUCCESS;
  298. }
  299.  
  300. /* get TIFF directory entry
  301.  */
  302. RC GtTiffEntry (DLOC *, DWORD, DIRENTRY *);
  303. LOCAL RC GtTiffEntry (pDloc, EntryOffset, pDe)
  304. DLOC    *pDloc;
  305. DWORD    EntryOffset;
  306. DIRENTRY    *pDe;
  307. {
  308.         RC err;
  309.  
  310.         /* get the 2 words beginning with deTag
  311.          */
  312.         if (err = GtData (pDloc, EntryOffset, 2, TIFFSHORT,
  313.          (LPSTR)&pDe->deTag)) {
  314.             return err;
  315.         }
  316.  
  317.         /* get the 2 dwords, beginning with deLength
  318.          */
  319.         if (err = GtData (pDloc, EntryOffset + 4L, 2, TIFFLONG,
  320.          (LPSTR)&pDe->deLength)) {
  321.             return err;
  322.         }
  323.  
  324.         /* return
  325.          */
  326.         return SUCCESS;
  327. }
  328.  
  329.  
  330. #define WORDS    1
  331. #define DWORDS    2
  332.  
  333. /* byte-reverse words or double-words in a file
  334.  */
  335. RC RevInFile (WORD, DWORD, WORD, FILE *);
  336. LOCAL RC RevInFile (which, dwPos, nItems, fp)
  337. WORD    which;    /* 1 = words, 2 = double words */
  338. DWORD    dwPos;
  339. WORD    nItems;    /* words or double words */
  340. FILE    *fp;
  341. {
  342.         RC        err = SUCCESS;
  343.         WORD    ItemSize;
  344.         DWORD    dwBytes;
  345.         char    *buf;
  346.         int        red;
  347.         
  348.         /* WORDS or DWORDS?
  349.          */
  350.         if (which == WORDS) {
  351.             ItemSize = 2;
  352.         } else {
  353.             ItemSize = 4;
  354.         }
  355.         
  356.         /* allocate
  357.          * 
  358.          * On the PC, this code will break if dwBytes is greater than 64k.
  359.          */
  360.         {
  361.             dwBytes = (DWORD)nItems * (DWORD)ItemSize;
  362.  
  363. #ifdef MACINTOSH            
  364.             if ((buf = mlalloc (dwBytes)) == (char *)NULL) 
  365. #endif
  366.  
  367. #ifdef WINDOWS
  368.             if ((buf = malloc ((unsigned)dwBytes)) == (char *)NULL) 
  369. #endif
  370.  
  371.             {
  372.                 printf ("RevInFile: mlalloc\n");
  373.                 err = -1;
  374.                 goto cu0;
  375.             }
  376.         }
  377.         
  378.         /* read
  379.          *
  380.          * note that we are restricted to 32K-byte reads!
  381.          */
  382.         {
  383.             if (err = fseek (fp, (long) (dwPos+TiffStart), 0)) {
  384.                 printf ("RevInFile: fseek error\n");
  385.                 goto cu1;
  386.             }
  387.             
  388.             if (dwBytes > MAXSHORT) {
  389.                 printf ("RevInFile: too large\n");
  390.                 err = -1;
  391.                 goto cu1;
  392.             }
  393.             
  394.             if ((red = fread (buf, ItemSize, (int)nItems, fp)) == 0) {
  395.                 printf ( "RevInFile: fread error\n");
  396.                 err = -1;
  397.                 goto cu1;
  398.             }
  399.         }
  400.         
  401.         /* reverse bytes within words or double words
  402.          */
  403.         if (which == WORDS) {
  404.             swab (buf, buf, (WORD)dwBytes);
  405.         } else {
  406.             swaw (buf, buf, (WORD)dwBytes);
  407.         }
  408.         
  409.         /* write
  410.          */
  411.         {
  412.             if (err = fseek (fp, (long) (dwPos+TiffStart), 0)) {
  413.                 printf ("RevInFile: fseek error\n");
  414.                 goto cu1;
  415.             }
  416.             
  417.             if ((red = fwrite (buf, ItemSize, (int)nItems, fp)) == 0) {
  418.                 printf ( "RevInFile: fread error\n");
  419.                 err = -1;
  420.                 goto cu1;
  421.             }
  422.         }
  423.  
  424.         /* return
  425.          */
  426. cu1:    free (buf);
  427. cu0:    return err;
  428. }
  429.  
  430.  
  431. /* byte-reverse a directory entry in a TIFF file
  432.  */
  433. RC RevEntry (DWORD, DIRENTRY *, FILE *);
  434. LOCAL RC RevEntry (dwPos, pde, fp)
  435. DWORD        dwPos;
  436. DIRENTRY    *pde;
  437. FILE        *fp;
  438. {
  439.         RC        err = SUCCESS;
  440.         WORD    tsize;
  441.         DWORD    dwBytesToRead;
  442.         DWORD    dwValPos;
  443.  
  444.         /* reverse tag, type
  445.          */
  446.         if (err = RevInFile (WORDS, dwPos, 2, fp)) {
  447.             printf ("RevEntry: tag,type\n");
  448.             goto cu0;
  449.         }
  450.         
  451.         /* reverse the length
  452.          */
  453.         if (err = RevInFile (DWORDS, dwPos + 4L, 1, fp)) {
  454.             printf ("RevEntry: length\n");
  455.             goto cu0;
  456.         }
  457.         
  458.         /* reverse the value
  459.          */
  460.         {
  461.             /* how many bytes to we have here?
  462.              */
  463.             if (err = GtTiffSizeof (pde->deType, &tsize)) {
  464.                 printf("RevEntry: GtTiffSizeof error\n");
  465.                 goto cu0;
  466.             }
  467.             dwBytesToRead = (DWORD)tsize * pde->deLength;
  468.                     
  469.             /* if less than 4, the value is right here
  470.              */
  471.             if (dwBytesToRead <= 4L) {
  472.                 dwValPos = dwPos + 8L;    /* deVal starts on byte 8, wit de */
  473.             }
  474.             
  475.             /* otherwise we need to work harder, and reverse the pointer as
  476.              * well as the data (if the data is not byte-oriented)
  477.              */
  478.             else {
  479.             
  480.                 /* reverse the pointer
  481.                  */
  482.                 if (err = RevInFile (DWORDS, dwPos + 8L, 1, fp)) {
  483.                     printf ("RevEntry: pointer\n");
  484.                     goto cu0;
  485.                 }
  486.                 
  487.                 /* calculate file position of the value
  488.                  */
  489.                 dwValPos = pde->deVal;
  490.             }
  491.             
  492.             /* read, reverse, and write, depending on the data type
  493.              */
  494.             switch (pde->deType) {
  495.             case TIFFBYTE:
  496.             case TIFFASCII:                
  497.                 break;
  498.             case TIFFSHORT:
  499.                 if (err = RevInFile (WORDS, dwValPos, pde->deLength, fp)) {
  500.                     printf ("error reversing SHORT values\n");
  501.                     goto cu0;
  502.                 }
  503.                 break;
  504.             case TIFFLONG:
  505.                 if (err = RevInFile (DWORDS, dwValPos, pde->deLength, fp)) {
  506.                     printf ("error reversing LONG values\n");
  507.                     goto cu0;
  508.                 }
  509.                 break;
  510.             case TIFFRATIONAL:
  511.                 if (err = RevInFile (DWORDS, dwValPos, pde->deLength * 2, fp)) {
  512.                     printf ("error reversing RATIONAL values\n");
  513.                     goto cu0;
  514.                 }
  515.                 break;
  516.             default:
  517.                 printf ("RevEntry: can't get here\n");
  518.                 err = -1;
  519.                 goto cu0;
  520.                 break;
  521.             }
  522.         
  523.         } /* end of value-reversing */
  524.             
  525. cu0:    return err;
  526. }
  527.  
  528.  
  529. /***************************** main routine **************************/
  530. #ifdef MACINTOSH
  531. int _main (int, char **);
  532. int _main (ac, av)
  533. #endif
  534.  
  535. #ifdef WINDOWS
  536. int main (int, char **);
  537. int main (ac, av)
  538. #endif
  539.  
  540. int ac;
  541. char **av;
  542. {
  543.          RC            err;
  544.          TIFFHDR        th;
  545.          DIRENTRY    de;
  546.          WORD        entries;
  547.         WORD        entry;
  548.          DWORD        location;
  549.         DLOC        dloc;
  550.         DWORD        dwtemp;
  551.         WORD        wtemp;
  552.         WORD        ByteOrder;
  553.         WORD        red;
  554.         register FILE    *fp;
  555.          
  556.          
  557.          /* check # of args
  558.           */
  559.          if (ac != 2) {
  560.              printf ("usage: filename\n");
  561.              goto cu0;
  562.          }
  563.          
  564.          /* open the input/output file
  565.           */
  566.          if ((fp = fopen (av[1], "r+b")) == (FILE *) NULL) {
  567.              printf ("can't open %s\n", av[1]);
  568.              goto cu0;
  569.          }
  570.          dloc.dlFp = fp;
  571.          printf ("FILE: %s\n", av[1]);
  572.         dloc.dlWhere = INFILE;
  573.  
  574.         /* since I use this program to process TIFF "files" that are embedded in
  575.          * other files (a nonstandard thing to do), I will look for a
  576.          * plausible start of the TIFF section.  TODO: make this more
  577.          * general (cycle through TIFF "files") and more robust (check for
  578.          * version #, at least).
  579.          */
  580.         while ((red = fread ((char *)&ByteOrder, sizeof(WORD), 1, fp)) == 1) {
  581.             if (ByteOrder == INTELTIFF || ByteOrder == MOTOROLATIFF)
  582.                 break;
  583.             else
  584.                 TiffStart += 2L;
  585.         }
  586.         printf("TiffStart=%lu\n",TiffStart);
  587.         printf("ByteOrder=%x\n",ByteOrder);
  588.         if (red == 0) {
  589.             printf ("can't find ByteOrder\n");
  590.             goto quit;
  591.         }
  592.         dloc.dlOrder = ByteOrder;
  593.  
  594.          /* read the 8-byte header, and dump it
  595.           */
  596.          if (err = GtTiffHdr (&dloc, &th)) {
  597.              printf ("can't read header\n");
  598.              goto quit;
  599.          }
  600.          if (th.thByteOrder == INTELTIFF) {
  601.              printf ("%6lu  ByteOrder = INTELTIFF", 0L);
  602.              printf ("  (converting to MOTOROLATIFF)\n");
  603.          }
  604.          else if (th.thByteOrder == MOTOROLATIFF) {
  605.              printf ("%6lu  ByteOrder = MOTOROLATIFF", 0L);
  606.              printf ("  (converting to INTELTIFF)\n");
  607.          }
  608.         else {
  609.             printf ("bad byte order.\n");
  610.             goto quit;
  611.         }
  612.          printf ("%6lu  Version = %d\n", 2L, th.thVersion);
  613.          printf ("%6lu  IfdOffset = %lu\n", 4L, th.thIfdOffset);
  614.          
  615.          location = th.thIfdOffset;
  616.         dloc.dlOrder = th.thByteOrder;
  617.         
  618.         /* change the byte order in the 8-byte header
  619.          */
  620.         {
  621.             /* byte order
  622.              */
  623.             {
  624.                 WORD    NewByteOrder;
  625.                 int        retval;
  626.                 
  627.                 if (th.thByteOrder == INTELTIFF) {
  628.                     NewByteOrder = MOTOROLATIFF;
  629.                 } else {
  630.                     NewByteOrder = INTELTIFF;
  631.                 }
  632.                 
  633.                 if ((retval = fseek (fp, 0L, 0)) != 0) {
  634.                     printf ("can't seek to byte 0\n");
  635.                     goto quit;
  636.                 }
  637.                 if ((retval = fwrite ((char *)&NewByteOrder, sizeof(NewByteOrder), 1, fp))
  638.                  == 0) {
  639.                     printf ("can't write new byte order\n");
  640.                     goto quit;
  641.                 }
  642.             }
  643.             
  644.             /* version:
  645.              */
  646.             if (err = RevInFile (WORDS, 2L, 1, fp)) {
  647.                  printf ("can't reverse header words\n");
  648.                  goto quit;
  649.             }
  650.             /* offset to 1st IFD:
  651.              */
  652.             if (err = RevInFile (DWORDS, 4L, 1, fp)) {
  653.                  printf ("can't reverse header words\n");
  654.                  goto quit;
  655.             }
  656.         }
  657.          
  658.          /* loop through the IFD's
  659.           */
  660.          do {
  661.              /* if ifd location is 0, quit
  662.               */
  663.              if (location == 0L) {
  664.                  printf ("ifd at 0. quit.\n");
  665.                  break;
  666.              }
  667.          
  668.              /* read the number of entries, and dump it
  669.               */
  670.              if (err = GtData (&dloc, (DWORD)location, 1, TIFFSHORT,
  671.               (LPSTR)&entries)) {
  672.                  printf ("can't read # of entries\n");
  673.                  break;
  674.              }
  675.              printf ("\n%6lu  Entries = %d\n", th.thIfdOffset, entries);
  676.              if (entries == 0) {
  677.                  printf ("number of entries is 0. quit.\n");
  678.                  break;
  679.              }
  680.              
  681.              /* reverse the number of entries
  682.               */
  683.              if (err = RevInFile (WORDS, location, 1, fp)) {
  684.                  printf ("can't reverse number of entries\n");
  685.                  goto quit;
  686.             }
  687.              
  688.              /* update location
  689.               */
  690.              location += 2;
  691.          
  692.              /* loop through the entries
  693.               */
  694.              for (entry = 0; entry < entries; entry++) {
  695.              
  696.                  /* read the entry, and dump it
  697.                   */
  698.                  if (err = GtTiffEntry (&dloc, location, &de)) {
  699.                      printf ("can't read entry\n");
  700.                      goto quit;
  701.                  }
  702. #if 0
  703.                 if (err = dumpentry (&dloc, location, &de)) {
  704.                     printf ("dumpentry error\n");
  705.                     goto quit;
  706.                 }
  707. #endif /* 0 */
  708.                 /* reverse the entry
  709.                  */
  710.                 if (err = RevEntry (location, &de, fp)) {
  711.                      printf ("can't reverse entry\n");
  712.                      goto quit;
  713.                 }
  714.                 
  715.                  /* adjust the current location
  716.                   */
  717.                  location += sizeof (DIRENTRY);
  718.                  
  719.              } /* end of entry loop */
  720.              
  721.              /* read the location of the next ifd
  722.               */
  723.              if (err = GtData(&dloc, (DWORD)location, 1, TIFFLONG,
  724.               (LPSTR)&dwtemp)) {
  725.                  printf ("%6lu  can't read location of the next ifd\n",
  726.                   location);
  727.                  goto quit;
  728.              }    
  729.              printf ("%6lu  next ifd at %lu\n", location, dwtemp);
  730.              location = dwtemp;
  731.              
  732.          } while (1); /* end of ifd loop */
  733.          
  734. quit:    ;
  735.          fclose (fp);
  736. cu0:    return;
  737. }
  738.